import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useState,} from 'react';
import {createForm} from '@formily/core';
import {createSchemaField, FormProvider} from '@formily/react';
import {
  ArrayCards,
  ArrayCollapse,
  ArrayItems,
  ArrayTable,
  ArrayTabs,
  Cascader,
  Checkbox,
  DatePicker,
  Editable,
  FormButtonGroup,
  FormCollapse,
  FormGrid,
  FormItem,
  FormLayout,
  FormStep,
  FormTab,
  Input,
  NumberPicker,
  Password,
  PreviewText,
  Radio,
  Select,
  Space,
  Submit,
  Switch,
  TimePicker,
  Transfer,
  TreeSelect,
  Upload,
} from '@formily/antd-v5';
import {GIcon} from '../Icon';
import {GFormProps} from './FormProps';
import {GFormSchema} from './FormSchema';
import {merge} from '../utils';
import {message} from 'antd';
import {GSelect} from '../Select';
import {request} from "../Request";
import {getSchema} from '../utils/SchemaUtils';

export const SchemaFieldComponents: any = {
  ArrayCards,
  ArrayCollapse,
  ArrayItems,
  ArrayTable,
  ArrayTabs,
  Cascader,
  Checkbox,
  DatePicker,
  Editable,
  FormButtonGroup,
  FormCollapse,
  FormGrid,
  FormItem,
  FormLayout,
  FormStep,
  FormTab,
  Input,
  NumberPicker,
  Password,
  PreviewText,
  Radio,
  Select,
  Space,
  Submit,
  Switch,
  TimePicker,
  Transfer,
  TreeSelect,
  Upload,
  GSelect,
};

const SchemaField: any = createSchemaField({
  components: SchemaFieldComponents,
  scope: {
    icon(name: string) {
      return React.createElement(GIcon, {type: name});
    },
  },
});

export const GForm = forwardRef((props: GFormProps, ref: any) => {
  const [schema, setSchema] = useState<GFormSchema>(props.schema);
  const [loading, setLoading] = useState(false);
  const [needLoadData, setNeedLoadData] = useState<boolean>(
    props.schema?.data?.autoload === true && props.schemaPath === undefined,
  );
  const [form] = useState(createForm());

  const onSubmit = useCallback((values: any): Promise<any> => {
    if (schema.data?.methodSubmit === 'none') {
      return Promise.resolve();
    }

    setLoading(true);
    let data: any = {...values};
    props.onSubmitting?.(data, schema);
    if (schema.data?.format === 'form') {
      const formData = new FormData();
      Object.keys(data).forEach((key) => {
        const value = data[key];
        if (value) {
          formData.append(key, value);
        }
      });
      data = formData;
    }

    return request(schema.data?.url, {
      method: schema.data?.methodSubmit || 'post',
      requestData: data,
      loadingSetter: form.setSubmitting,
      errMsg: '提交数据失败',
      getResponse: true
    }).then((resp) => {
      if (resp.status === 200) {
        if (props.onSubmitted) {
          props.onSubmitted(resp.data, resp);
        } else {
          message.success('成功');
        }
      } else {
        message.error('提交数据失败');
        return Promise.reject(resp);
      }
      return resp;
    }).finally(() => {
      setLoading(false);
    });
  }, []);

  const submit = useCallback((): Promise<any> => {
    return form.validate().then(() => {
      return onSubmit(form.values);
    });
  }, []);

  const loadData = useCallback(() => {
    props.onDataLoading?.(schema);

    const requestMethod = schema.data?.methodLoad || 'get';
    const requestData = schema.data?.filter ?? {};
    if (schema.data?.include) {
      requestData.include = schema.data?.include;
    }

    request<any>(schema.data?.urlLoad ?? schema.data?.url, {
      method: requestMethod,
      requestData: requestData,
      loadingSetter: form.setSubmitting,
      errMsg: '获取数据错误',
    }).then(resp => {
      setNeedLoadData(false);
      let data = resp;
      data = props.onDataLoaded?.(data) || data;
      form.setInitialValues(data);
    })
  }, []);

  useImperativeHandle(ref, () => ({
    submit: submit,
    loadData: (id?: any) => {
      setSchema((schema: GFormSchema) => {
        return merge(schema, {
          data: {
            id: id,
          },
        });
      });
      setNeedLoadData(true);
    },
    getForm: () => form,
  }));

  useEffect(() => {
    if (props?.schemaPath) {
      getSchema<GFormSchema>(props.schemaPath, form.setSubmitting)
        .then(remoteSchema => {
          setSchema((schema: GFormSchema) => {
            const newSchema = merge(remoteSchema, props.schema, schema);
            props.onSchemaLoaded?.(newSchema);
            if (newSchema.data?.autoload) {
              setNeedLoadData(true);
            }
            return newSchema;
          });
        });
    }
  }, [props.schemaPath]);

  useEffect(() => {
    if (schema?.data?.url && needLoadData) {
      loadData();
    }
  }, [schema, needLoadData]);

  useEffect(() => {
    if (!props.schemaPath && props.schema) {
      setSchema(props.schema);
    }
  }, []);

  return (
    <FormProvider form={form}>
      <FormLayout labelCol={6} wrapperCol={12} {...schema?.layout}>
        <SchemaField schema={schema?.fields}/>
        {schema?.layout?.submit && (
          <FormButtonGroup.FormItem>
            <Submit
              {...schema?.layout?.submit?.['x-component-props']}
              onSubmit={onSubmit}
              loading={loading}
            >
              {schema?.layout?.submit?.text || '确定'}
            </Submit>
          </FormButtonGroup.FormItem>
        )}
      </FormLayout>
    </FormProvider>
  );
});
